import matplotlib.pyplot as plt
from scipy.optimize import minimize_scalar
import emoji

# 设置博弈参数
# 测试例子：100,10,20,30
print("请设置博弈参数")
str_emoji = ':smiling_face_with_hearts:' * 3
print(emoji.emojize(str_emoji, language='alias', variant="emoji_type"))

print("请输入需求参数：")
a = int(input())
# 需求斜率，表示价格变化时的需求变化
print("请输入需求斜率:")
b = int(input())
# 领导者的成本
print("请输入领导者的成本:")
c1 = int(input())
# 追随者的成本
print("请输入追随者的成本:")
c2 = int(input())


# 计算领导者的利润
def leader_profit(q1, q2):
    # q1是领导者的生产量
    # q2是追随者的生产量
    # 计算价格
    price = a - b * (q1 + q2)
    # 计算利润
    profit = (price - c1) * q1
    return profit


# 计算追随者的利润
def follower_profit(q1, q2):
    # 计算价格
    price = a - b * (q1 + q2)
    # 计算利润
    profit = (price - c2) * q2
    return profit


# 寻找追随者的最优响应
def best_response(q1):
    # 使用minimize_scalar函数来找最优策略
    # q2是追随者的生产量
    # bounds = (0, 100)指定了q2的取值范围在0到100之间
    # method指明优化算法的类型，bounded算法用于处理有界区间的标量函数最小化问题
    # lambda函数实际上是在寻找follower_profit的最大值，即追随者的最大利润
    result = minimize_scalar(lambda q2: -follower_profit(q1, q2), bounds=(0, 100), method='bounded')
    return result.x


# 根据追随者的最优响应求解领导者的最优策略
def optimal_leader_strategy():
    # 初始化最优生产量和利润
    best_q1 = 0
    max_profit = 0

    # 遍历领导者的生产量
    # q1的范围设置从0到100
    for q1 in range(101):
        # 计算追随者的最佳回应
        q2 = best_response(q1)
        # 计算领导者的利润
        profit = leader_profit(q1, q2)
        # 跟最大利润进行比较，调整价格和目前的利润
        if profit > max_profit:
            max_profit = profit
            best_q1 = q1

    return best_q1, max_profit


# 博弈测试
def main():
    print("您好，欢迎使用stackelberg博弈模型！")
    str_emoji1 = ":sparkling_heart:" * 3
    print(emoji.emojize(str_emoji1, language='alias', variant="emoji_type"))

    q1, profit = optimal_leader_strategy()
    # 追随者根据领导者的生产量选择自己的最佳生产量
    q2 = best_response(q1)

    # 绘制饼状图展示分配情况，能直观地展示领导者与追随者的最佳策略
    print("输出stackelberg博弈生产量分配图")
    # 设置标签和参数
    labels = ['Leader Production', 'Follower Production']
    sizes = [q1, q2]

    # 饼图的每个扇区的大小由sizes决定
    # autopct用于指定饼图中每个扇区的百分比显示格式，这里我们选择保留一位小数
    plt.pie(sizes, labels=labels, autopct='%1.1f%%')
    # 饼图的标题
    plt.title('Stackelberg Game Production Distribution')
    plt.show()

    # 引入emoji库中的表情，使输出更加人性化
    print("测试结束，欢迎下次使用！")
    str_emoji2 = ':rose:' * 3
    print(emoji.emojize(str_emoji2, language='alias', variant="emoji_type"))


if __name__ == '__main__':
    main()